// ==UserScript==
// @name         ACG_详情_新篇章
// @version      3.0.1
// @description  自动评论管理、定位网盘链接、资源嗅探(脚本写的有点烂~ o(*￣▽￣*)o 嗯……，能用，就懒得改了(程序第一定律，能跑就不要动))
// @author       cy2
// @match        https://note.acgyouxi.xyz/thread*
// @match        https://bbs.acgyouxi.vip/thread*
// @match        https://live.yuanacg.com/thread*
// @match        https://south.yuanacg.com/thread*
// @match        https://note.yuanacg.com/thread*
// @match        https://note.996flh.com/thread*
// @match        https://note.2046acg.com/thread*
// @match        https://east.2046acg.com/forum.php?mod=viewthread*
// @icon         
// @homepage     https://gitee.com/caiyaoyuan/script-sets/tree/master/JavaScript
// @namespace    https://gitee.com/caiyaoyuan/script-sets/blob/master/JavaScript/acgManage2.js
// @updateURL    https://gitee.com/caiyaoyuan/script-sets/raw/master/JavaScript/acgManage2.js
// @installURL   https://gitee.com/caiyaoyuan/script-sets/raw/master/JavaScript/acgManage2.js
// @downloadURL  https://gitee.com/caiyaoyuan/script-sets/raw/master/JavaScript/acgManage2.js
// @grant        unsafeWindow
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @connect      localhost
// @connect      127.0.0.1
// @connect      10.147.19.45
// @connect      10.147.19.46
// @connect      10.147.19.48
// @connect      10.147.19.49
// @connect      10.147.19.50

// @note         3.0.1 资源嗅探,支持选择并锁定aria2分组下载，减少重复选择
// @note         3.0.0 自动评论管理、定位网盘链接、资源嗅探
// ==/UserScript==

(function() {
    'use strict';

    // 有需求请在这里配置,生效等级高于默认配置项（）
    var customs_configs = {
        snifferEnable:true, // 嗅探下载连接（需要配置有效resolveUrl），方便直接下载(可通过管理组件控制)
        snifferManagerEnable:true, // 嗅探 管理组件
        //resolveUrl: "http://localhost:1468/netdisk/resolve/v2",
        resolveUrl: "http://10.147.19.49:1468/netdisk/resolve/v2",
        aria2GroupEnable: true,
        aria2GroupConfig: { // 请配置为自己的aria2推送地址，和token(未设置就留空)
            "46-16823": {
                aria2DownloadUrl: "http://10.147.19.46:16823/jsonrpc",
                aria2DownloadToken: "1qaz2wsx3edc",
            },
            "48-16823": {
                aria2DownloadUrl: "http://10.147.19.48:16823/jsonrpc",
                aria2DownloadToken: "1qaz2wsx3edc",
            },
        }
    }

    // 默认配置项
    var default_configs = {
        commentEnable: false, // 自动评论
        commentManagerEnable: true, // 评论 管理组件 开关
        commentMessageType: "random",// 自动评论值来源类型 random | default
        commentMessageDefault: "不错，又占了一个沙发！", // 当commentMessageType=default时，评论使用该条消息
        commentMessageList: [ // 评论消息列表，当commentMessageType=random时，从列表中随机获取一条
                "不错，又占了一个沙发！",
                "666666666666666666666",
                "啥也不说了，楼主就是给力！",
                "膜拜神贴，后面的请保持队形~",
        ],
        commentMessageUpperLimit: new RegExp(".*(您所在的用户组每小时限制发回帖[\\s]*(\\d+)[\\s]*个).*", "gi"), // 评论次数达最大上限匹配规则
        positionMessageEnable: true, // 定位网盘或评论 管理组件 开关，方便直达到（回复、网盘处或回顶部）
        snifferManagerEnable: false, // 嗅探 管理组件 开关
        snifferEnable: false, // 嗅探下载连接（需要配置有效resolveUrl），方便直接下载(可通过管理组件控制)
        resolveUrl: "http://localhost:1464/netdisk/resolve/v2",
        idmDownloadUrl: "http://localhost:7178/select", //这是IDM推送地址，禁止更改(还未集成)
        aria2DownloadUrl: "http://localhost:6800/jsonrpc", //这里是Aria2下载推送地址，本地默认不需要更改
        aria2DownloadToken: "", //这里是Aria2下载推送token，默认不需要设置
        aria2GroupEnable: false,
        aria2GroupConfig: { // local 分组为默认项，即上部分配置，请勿占用(不会起作用，在这里仅作为示例模板),
            //"local": {
            //    aria2DownloadUrl: "http://localhost:6800/jsonrpc",
            //    aria2DownloadToken: "",
            //}
        }
    }

    // 操控窗口配置（不建议修改）
    var html_configs = {
        htmlTemmplate: {
            position:`<div style="" id="resource-position"><style>@keyframes halo { 0% {box-shadow: 0px 0px 0px #fd0101;} 25% {box-shadow: 0px 0px 10px #fd0101;} 50% {box-shadow: 0px 0px 20px #fd0101;} 100% {box-shadow: 0px 0px 30px #fd0101;}} .d-none{display: none;} .cursor-pointer{cursor: pointer;} .color-gold{color: gold;}.bg-color-green{background-color: green;}.bg-color-red{background-color: red;}.align-flex-center,.align-self-center{align-self: center}.align-flex-start,.align-self-start{align-self: flex-start;}.align-flex-end,.align-self-end{align-self: flex-end;} .show-link{} .show-link:hover{color:#f00} #resource-position>.resource-position-default:not(:first-child){margin-top: 0.75em;}
#resource-position{position: fixed;top: 10vh;left: 3%;z-index: 999999; }#resource-position .resource-position-default{animation: halo 2.5s linear 1;animation-iteration-count: infinite;animation-direction: alternate;width: 8em;height: 8em;background: #FFF;border: 5px solid #1ec9e0;border-radius: 50%;box-shadow: 0px 0px 30px #fd0101;overflow: hidden;}
#resource-position .resource-position-default>.resource-position-item{width: 100%;height: calc(50% - 2px);border: none;text-align: center;display: flex;justify-content: center;font-size: 16px;}#resource-position .resource-position-default>.resource-position-item:fir/st-child{border-bottom: 1px solid red;margin-bottom: 2px;}#resource-position .resource-position-default>.resource-position-item:last-child{border-top: 1px solid red;margin-top: 2px;}</style>`,
            resource: `<div class="resource-position-default"><div class="resource-position-item"></div><div class="resource-position-item"></div></div></div>`,
            comment_checkbox: `<label style="align-self:flex-end;"><input type="checkbox" data-true="当前已勾选自动评论" data-false="当前已取消自动评论"><spam>自动评论</span></label>`,
            comment_hint: `<span id="comment-hint" class="align-flex-center show-link" data-status="false">未评论</span>`,
            show_link: `<a class="show-link"></a>`,
            sniffer_checkbox: `<label class="align-self-end"><input type="checkbox" data-true="当前已勾选自动采集" data-false="当前已取消自动采集"><spam>自动采集</span></label>`,
            sniffer_container: `<div id="sniffer-container"><style>#sniffer-container{position: absolute;left: 7em;bottom:-2em;background-color:rgba(16,16,16,0.7);border: 1px solid #1ec9e0;border-radius: 10px;padding: 5px;display: none;flex-flow: column;width: 70vw;} .sniffer-container-item{border-bottom: 2px solid #fff;padding-bottom: 3px;} #download-container>.download-hint-item{border-radius: 5px;color: #fff;padding: 0.5em;} #info-container{color: #fff;font-size: 20px; font-weight: 700;} #sniffer-container table th,#sniffer-container table td{text-align: center;}#sniffer-container table tr.resolve-error td,#sniffer-container table tbody tr.resolve-error td a{text-decoration: line-through;text-decoration-color: #ffd200;color: #ffd200;} #sniffer-container table, #sniffer-container table th,#sniffer-container table td,#sniffer-container table a{color:#fff;}</style>
            <div id="download-container" class="sniffer-container-item d-none"><div class="download-hint-item"><span class="date-text"></span> &gt; <span class="source-text"></span> - <span class="filename-text"></span> - <span class="type-text"></span> <span class="status-text"></span><div class="casus-container" class="d-none">原因：<span class="casus-text"></span></div></div></div><div id="info-container" class="sniffer-container-item"></div><table style="font-weight: 600;"><thead><tr><th rowspan="2">来源(可能不准确）</th><th rowspan="2">网址</th><th rowspan="2">文件名</th><th rowspan="2">密码</th><th colspan="3">下载</th></tr><tr><th>浏览器</th><th>IDM</th><th>aria2<span id="aria2-locked"></span></th></tr></thead><tbody></tbody></table></div>`,
            sniffer_hint: `<div id="sniffer-hint" data-change="false" data-status="false">立即采集</div>`,
            aria2_container: `<select><option value="local">local</option></select>`,
        },
        commentLinkConf:{
            mark:[
                { text:"去评论", status:false, addClass:"", removeClass:"color-gold" },
                { text:"已评论", status:true, addClass:"color-gold", removeClass:"" }
            ],
            class:"color-gold"
        },
        positionLinkConf:{
            mark:[
                { text:"回顶部", with:"#hd", hash:"_top_hash_mark", class:"align-self-center" },
                { text:"回复/网盘", with:".showhide,.locked", hash:"_look_hash_mark", class:"align-self-center" },
            ]
        },
        flags:{
            append_parent: true,
        },
    }


    // 合并出所有可配置项
    var controls = Object.assign({}, default_configs, customs_configs, html_configs);

    if(controls.aria2GroupEnable){
        controls.aria2GroupConfig.local = {
            aria2DownloadUrl: controls.aria2DownloadUrl,
            aria2DownloadToken: controls.aria2DownloadToken,
        }
        let a2c = controls.htmlTemmplate.aria2_container;
        let html = "";
        for(let key in controls.aria2GroupConfig) {
            if(key != "local"){
                html += `<option value="` + key + `">` + key + `</option>`;//拼接其他选项
            }
        }
        if(html != "" && html.length > 0) {
            let i = a2c.lastIndexOf("</select>");
            controls.htmlTemmplate.aria2_container = a2c.substr(0, i) + html + a2c.substr(i);//拼接完整选项并替换
        }
    }
    //console.info("controls", controls);
    //console.info("customs_configs", customs_configs);
    //console.info("default_configs", default_configs);

    var $rp, $dc;
    var JQ = unsafeWindow.jQuery;
    var path = (unsafeWindow.location.pathname + unsafeWindow.location.search) || unsafeWindow.location.href; // 不建议使用 href，可能再定位时的锚点信息也记录进去
    var mark = window.btoa(path);
    console.info(mark, path);

    // 设置cookie
    function setCookie(key,val,time){
        var eps = new Date(new Date().getTime() + ((time||0) * 1000));
        //console.info( key + "=" + val + ";expires=" + eps.toGMTString())
        document.cookie = key + "=" + val + ";expires=" + eps.toGMTString();
    }

    // 获取cookie
    function getCookie(key, cookies){
        let arr = (cookies || document.cookie).match(new RegExp("(^| )" + key + "=([^;]*)(;|$)"));
        return arr ? unescape(arr[2]) : null;
    }

    function getGmValuEnable(name){
        let val = GM_getValue(name);
        if(val == undefined){
           GM_setValue(name, val = controls[name]);// 初始化
        }
        return val;
    }
    // 获取本地评论开关
    function getLocalCommentEnable(){
        //let comment = localStorage.comment;
        //if(comment == undefined){
        //   localStorage.comment = comment = controls.commentEnable; // 初始化
        //}
        //return comment;
        return getGmValuEnable("comment");
    }


    function getLocalSnifferEnable(){
        //let sniffer = localStorage.sniffer;
        //if(sniffer == undefined){
        //   localStorage.sniffer = sniffer = controls.snifferEnable; // 初始化
        //}
        //return sniffer;
        return getGmValuEnable("sniffer");
    }

    // 格式化时间
    Date.prototype.format = function(fmt) {
		if(!fmt){
			fmt = "yyyy-MM-dd HH:mm:ss:S";
		}
        let opt = {
                "M+" : this.getMonth()+1,                 //月份
                "d+" : this.getDate(),                    //日
                "h+" : this.getHours()%12, 				  //小时   12小时制
                "H+" : this.getHours(),                   //小时   24小时制
                "m+" : this.getMinutes(),                 //分
                "s+" : this.getSeconds(),                 //秒
                "q+" : Math.floor((this.getMonth()+3)/3), //季度
                "S"  : this.getMilliseconds()             //毫秒
        };
        if(/(y+)/.test(fmt)){
            fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
        }
        for(let k in opt){
            if(new RegExp("("+ k +")").test(fmt)) {
                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (opt[k]) : (("00"+ opt[k]).substr((""+ opt[k]).length)));
            }
        }
        return fmt;
    };

    function panelManager(){

        let $body = JQ("body");
        let ht = controls.htmlTemmplate;
        $rp = JQ(ht.position).appendTo($body);

        if(controls.commentManagerEnable){ // 显示评论管理
            let $rpd = JQ(ht.resource).appendTo($rp);
            let rpis = $rpd.find(".resource-position-item");
            let commentCheckbox = JQ(ht.comment_checkbox).appendTo(rpis.eq(0));
            let checkbox = commentCheckbox.find("[type=checkbox]").on("change", function(e){
                let $this = JQ(this);
                let status = $this.prop('checked');
                //localStorage.comment = status;
                GM_setValue("comment", status);
            });
            let localCommentEnable = getLocalCommentEnable();
            if(localCommentEnable){
                checkbox.trigger("click");
            }
            JQ(ht.comment_hint).appendTo(rpis.eq(1)).bind("click", "[data-status=false]:not(:disabled)", function(){
                let $this = JQ(this).attr("data-status", true);
                comment(true);
            });
        }

        if(controls.positionMessageEnable){ // 显示定位管理
            let rpi = JQ(ht.resource).appendTo($rp).find(".resource-position-item");
            for(let i in controls.positionLinkConf.mark){
                let it = controls.positionLinkConf.mark[i];
                if(typeof it != "object"){
                    break;
                }
                JQ(ht.show_link).data("conf",it).text(it.text).addClass(it.class).attr("href", path+"#"+it.hash).appendTo(rpi.eq(i)).bind("click", function(){
                    if (JQ("#"+it.hash).length == 0) {
                        JQ(ht.show_link).attr("id", it.hash).attr("name", it.hash).insertBefore(JQ(it.with));
                        if (JQ("#"+it.hash).length == 0) {
                            console.warn("无法定位到:" + it.text);
                            return false;
                        }
                    }
                });
            }
        }

        if(controls.snifferManagerEnable){ // 显示嗅探管理
            let $rpd = JQ(ht.resource).appendTo($rp);
            let rpis = $rpd.find(".resource-position-item");
            let snifferCheckbox = JQ(ht.sniffer_checkbox).appendTo(rpis.eq(0));
            let checkbox = snifferCheckbox.find("[type=checkbox]").on("change", function(e){
                let $this = JQ(this);
                let status = $this.prop('checked');
                //localStorage.sniffer = status;
                GM_setValue("sniffer", status);
            });
            let localSnifferEnable = getLocalSnifferEnable();
            if(localSnifferEnable){
                checkbox.trigger("click");
            }

            rpis.eq(1).append(JQ(ht.sniffer_hint)).on("click", "[data-change][data-status=false]:not(:disabled)", function(){
                let $this = JQ(this).attr("data-status", true);
                sniffer(true);
            }).on("click", "[data-change]:not(:disabled):not([data-status=false])", function(){
                let $this = JQ(this);
                let change = $this.attr("data-change");
                let $snifferCcontainer = JQ("#sniffer-container");
                if(change == "true"){
                    $this.attr("data-change", false);
                    $snifferCcontainer.css("display", "flex");
                } else if(change == "false"){
                    $this.attr("data-change", true);
                    $snifferCcontainer.css("display", "none");
                }
            });

            let $sc = JQ(ht.sniffer_container).appendTo(rpis.eq(1));
            $sc.find("#info-container").text(JQ("#thread_subject").text());
            if(controls.aria2GroupEnable){
                let $al = $sc.find("#aria2-locked");
                let $ac = JQ(controls.htmlTemmplate.aria2_container).appendTo($al);
                $ac.bind("change", function(e){
                    //console.info("change", e);
                    let val = JQ(e.target).find(":checked").val();
                    GM_setValue("aria2-locked", val);
                });
                let aria2locked = GM_getValue("aria2-locked", "local");
                if(aria2locked){
                    $ac.find("option[value='"+aria2locked+"']").prop("selected", true);
                }
            }
        }
    }

    // 发送评论
    function sendCommentMessageAjax(url, data){
        let $replyHint = JQ("#reply-hint")
        if(!$replyHint || $replyHint.length == 0){
           $replyHint = JQ(`<div id="reply-hint" style="display:none;color:red;font-size:20px;"></div>`).prependTo(JQ(".locked"));
        }
        JQ.ajax({
            url:url,
            type:"post",
            data:data,
            dataType: "text",
            success:function(data){
                let result;
                let curDate = new Date();
                let curDateFormat = curDate.format();
                console.info(data)
                if(result = controls.commentMessageUpperLimit.exec(data)){ // 评论次数达每小时最大上限,
                    let t1 = (10 * 60);// 默认 600秒
                    let lastDate = new Date(curDate.getTime() + (t1 * 1000));
                    let lastDateFormat = lastDate.format();
                    setCookie(mark, "autoReply", t1);
                    $replyHint.html("<span>评论返回通知："+result[1]+"<br>当前时间：<span style='color: blue;'>"+curDateFormat+"</span>, 截止至 <span style='color: blue;'>"+lastDateFormat+"</span> 之前将不再自动评论！！</span>").css("display","block");
                    JQ("#fwin_reply").css("display","none");
                    console.info(result[0], "当前时间："+curDateFormat+" 截止至 "+lastDateFormat+" 之前将不再自动评论！！");
                    console.wran(result[0], "当前时间："+curDateFormat+" 截止至 "+lastDateFormat+" 之前将不再自动评论！！");
                    return;
                } else {
                    setCookie(mark, "autoReply", 30); // 评论成功
                    location.reload(); // 刷新页面
                }
            },error:function(){
                console.error("自动评论失败", ...arguments);
                alert("自动评论失败");
            }
        });
    }

    // 配置评论参数
    function setCommentMessageParams($postform){
        if($postform){
            var url = $postform.attr("action")+"&inajax=1";
            var message = controls.commentMessageDefault;
            if(controls.commentMessageType === "random" && controls.commentMessageList && controls.commentMessageList.length > 0){ // 开启随机且有随机消息列表
               message = controls.commentMessageList[Number.parseInt(Math.random() * 1000) % (controls.commentMessageList.length)];
            }
            if(message === "" || message.trim() === ""){
               message = controls.commentMessageDefault || "不错，又占了一个沙发！";
            }
            $postform.find("#postmessage").val(message);
            var data = $postform.serialize();
            sendCommentMessageAjax(url, data);
        } else {
            console.error("自动评论 $postform 标签元素丢失", ...arguments);
            alert("自动评论 $postform 标签元素丢失");
        }
    }

    function commentHintUpdate(status){
        let $ch = JQ("#comment-hint");
        if($ch.length == 0){
            return;
        }
        let mark = controls.commentLinkConf.mark;
        if(Array.isArray(mark) && mark.length >= status){
            let it = mark[status];
            $ch.text(it.text).attr("data-status", it.status).addClass(it.addClass).removeClass(it.removeClass);
        } else {
            $ch.text("去评论").attr("data-status", false).removeClass(controls.commentLinkConf.class);
        }
    }

    // 评论
    function comment(flag){
        let locked = document.querySelector(".locked");
        let showhide = document.querySelector(".showhide");
        if(locked != null){
            commentHintUpdate(0);
        } else if(showhide != null){
            commentHintUpdate(1);
        }
        let localCommentEnable = getLocalCommentEnable();
        if(flag || localCommentEnable){
            var $append_parent = JQ("#append_parent");
            //console.info($append_parent)
            if($append_parent.length != 0 && $append_parent.data("flag") == undefined){
                $append_parent.data("flag", true).bind("DOMNodeInserted",function(e){
                    var $ele = JQ(e.target);
                    //console.info("- inserted -", this, $ele, e.target, e);
                    if($ele.is("#postform")){
                        setCommentMessageParams($ele);
                    }
                });
            }
            var markCookie = getCookie(mark); // 是否已评论
            if(locked != null && !markCookie){
                 let $locked_a = JQ(locked).find("a");
                //console.info("- .locked -", $locked_a);
                $locked_a.trigger("click");
            }
        }
    }

    var snifferTotal = 0, snifferCount = 0;
    var snifferHintTest = {
        "default":{ "color":"#dd5252", disabled: true },
        "-10":{ text:"不处理", },
        "-9":{ text:"未开启", disabled: false },
        "-8":{ text:"未评论", },
        "-1":{ text:"无采集源", },
    }
    function snifferHintUpdate(flag, step){
        let $snifferHint = JQ("#sniffer-hint");
        if($snifferHint.length == 0){
            return;
        }
        if(step != undefined && snifferHintTest[step]){
            let info = Object.assign({}, snifferHintTest.default, snifferHintTest[step]);
            $snifferHint.text(info.text).css("color", info.color).prop("disabled", info.disabled);
        } else if(step >= 0) {
            snifferCount += step;
            if(snifferCount == 0 || snifferTotal == 0){
                $snifferHint.text("未采集").css("color","#333").prop("disabled", true);
            } else if(snifferCount > 0 && snifferTotal > 0 && snifferCount < snifferTotal){
                $snifferHint.text("采集中").css("color","#333").prop("disabled", true);
            } else if(snifferCount >= snifferTotal){
                $snifferHint.attr("data-status", true);
                let $snifferCcontainer = JQ("#sniffer-container");
                if($snifferCcontainer.find("table tbody tr").length > 0){
                    $snifferHint.text("采集完成").css("color","#6ce71c").prop("disabled", false);
                    $snifferCcontainer.css("display", "flex");
                } else {
                    $snifferHint.text("校验无源").css("color","#333").prop("disabled", true);
                    $snifferCcontainer.css("display", "none");
                }
            }
        }
    }

    function snifferDownloadUrl(url, urlSource, pwd){
        if(!controls.resolveUrl){
            console.warn("未配置嗅探服务器地址");
            alert("未配置嗅探服务器地址");
            return;
        }
        if(!!url && url.trim() != "#"){

            let param = 'url=' + url;
            GM_xmlhttpRequest({
                method: "post",
                url: controls.resolveUrl,
                data: param,
                headers: { "Content-Type": "application/x-www-form-urlencoded" },
                onload: function (res) {
                    snifferHintUpdate(true, 1);
                    let result = JSON.parse(res.response);
                    console.info(url + " ===> " + res.response);
                    let $sc = JQ("#sniffer-container");
                    if($sc.is(":hidden")){
                        $sc.css("display","flex");
                    }
                    let domain = "", r;
                    if(r = new RegExp("https?://(?<domain>[\\w\\.]+)(/?.*)").exec(url)){
                        domain = r.groups.domain;
                    }
                    let $tr = JQ(`<tr><td><a href=`+url+`">`+urlSource+`</a></td><td style="">`+domain+`</td><td>`+(result.filename || "未知")+`</td><td>`+pwd+`</td>
                    <td>不支持</td><td>不支持</td>
                    <td class="aria2Download">` + (controls.aria2GroupEnable ? controls.htmlTemmplate.aria2_container : "") + `<span class="aria2DownloadBtn">下载</span></a></td></tr>`);
                    if(controls.aria2GroupEnable){
                        let aria2locked = GM_getValue("aria2-locked", "local");
                        $tr.find(".aria2Download select option[value='"+aria2locked+"']").prop("selected", true);
                    }
                    if (result.ok && result.code === 0) {
                        let row = { url: url, urlSource: urlSource, pwd: pwd }
                        $tr.data("info", result).data("row", row);
                        $tr.on("click", ".aria2DownloadBtn", function(e){
                            let group = "local";
                            if(controls.aria2GroupEnable) {
                                group = e.currentTarget.previousElementSibling?.selectedOptions[0].value;
                                if(!group){
                                    alert("未选择推送分组");
                                    return;
                                }
                            }
                            let conf = controls.aria2GroupConfig[group];
                            aria2Download(conf, e, $tr || JQ(e.delegateTarget), JQ(e.currentTarget), result, row);
                            //console.info("click .aria2DownloadBtn", conf, e, this, result, row);
                        });
                    } else {
                        let hintInfo = url + " 向 " + controls.resolveUrl + " 采集失败" + result.message;
                        $tr.addClass("resolve-error").attr("title", hintInfo)
                            .find(".aria2Download").html("采集失败");
                        console.info(hintInfo);
                    }
                    $tr.appendTo($sc.find("table tbody"));
                },
                onerror: function (err) {
                    snifferHintUpdate(true, 1);
                    console.info(url + " 向 " + controls.resolveUrl + " 采集失败 "+ JSON.stringify(err));
                }
            });
        }

    }

    function getUrlAndPwdSourceText(sourceText, splitText){
        let sourceObj = { "urls":{}, "pwds":{} };
        if(sourceText != undefined && sourceText.trim().length > 0){
            let urls = {}, pwds = {};
            let texts = sourceText.split(splitText);
            for(let text of texts){
                let rurl = /\s*((.*)下载)[:：]([a-zA-z]+:\/\/[^\s]*|^http:\/\/([\w-]+\.)+[\w-]+(\/[\w-.\/?%&=]*)?$)\s*/.exec(text);
                if(rurl != undefined){
                    urls[rurl[3]] = rurl[1];
                } else {
                    let rpwd = /\s*(解压密码)\s*[:：]\s*([\w\.]+)\s*/.exec(text);
                    if(rpwd != undefined){
                        pwds.pwd = rpwd[2];
                    }
                }
            }
            sourceObj.urls = urls;
            sourceObj.pwds = pwds;
        }
        return sourceObj;
    }

    // 嗅探
    function sniffer(flag){
        let localSnifferEnable = getLocalSnifferEnable();
        let status = (flag || localSnifferEnable) && controls.snifferManagerEnable;
        if(!status) {
            snifferHintUpdate(status, -9);
            return;
        } else {
            // .locked和.showhide两标志类是互斥的
            let lockedNode = document.querySelector(".locked");
            let showhideNode = document.querySelector(".showhide");
            if(lockedNode instanceof Node){
                 snifferHintUpdate(flag, -8);
            } else if(showhideNode instanceof Node) {
                let aNodeList = showhideNode.querySelectorAll(".showhide a");
                if(aNodeList instanceof NodeList && aNodeList.length > 0){
                    let strongNode = showhideNode.querySelector("strong");
                    let sourcesText = getUrlAndPwdSourceText(strongNode instanceof Node ? strongNode.textContent : "", "\n\n");
                    snifferTotal = aNodeList.length;
                    snifferCount = 0;
                    snifferHintUpdate(true, 0);
                    for(let anode of aNodeList){
                        let href = anode.getAttribute("href");
                        snifferDownloadUrl(href, sourcesText.urls[href], sourcesText.pwds.pwd);
                    }
                } else {
                    snifferHintUpdate(flag, -1);
                }
            } else if(lockedNode == null && showhideNode == null) {
                snifferHintUpdate(flag, -10);
            }
        }
    }

    function snifferDownloadHint(type, rows, casusText){
        if($dc == undefined){
            $dc = JQ("#download-container");
        }
        if($dc != undefined){
            let $dhi = $dc.removeClass("d-none").find(".download-hint-item").removeClass("bg-color-red bg-color-green").addClass(type ? "bg-color-green" : "bg-color-red");
            rows.status = (type ? "下载推送成功" : "下载推送失败");
            for(let key in rows){
                let flagClass = "."+key+"-text";
                $dhi.find(flagClass).text(rows[key]);
            }
            let $cc = $dhi.find(".casus-container");
            if(type){
                $cc.addClass("d-none");
            } else {
                $cc.removeClass("d-none").find(".casus-text").text(casusText || "未知");
            }
        }

    }

    function aria2Download(conf, e, $tr, $td, data, row, filePostFix = ""){
        console.info("aria2Download", conf, e, $tr, $td, data, row, filePostFix);
        let rows = {
            date: new Date().format("yyyy-MM-dd HH:mm:ss"),
            source: row.urlSource,
            type: "aria2",
            filename: data.filename,
        }
        if(!conf.aria2DownloadUrl){
            //snifferDownloadHint(0, rows, "未配置Aria2下载推送地址");
            alert("未配置Aria2下载推送地址");
            return;
        }
        GM_xmlhttpRequest({
            method: "post",
            url: conf.aria2DownloadUrl,
            data: JSON.stringify({ "jsonrpc": "2.0", "method": "aria2.addUri", "id": "QXJpYU5nXzE2NjEwNzQzNTBfMC44OTUwMDYzNDAzOTE3MDE3", "params": ["token:"+conf.aria2DownloadToken || "",[data.durl], { "out": data.filename + filePostFix, "referer": data.turl || data.surl }] }),
            headers: { "Content-Type": "application/json" },
            onload: function (res) {
                if (res.status === 200) {
                    snifferDownloadHint(1, rows, "Aria2下载推送成功~");
                } else if (res.status != undefined) {
                    snifferDownloadHint(0, rows, "Aria2 "+res.status+"错误,请检查~");
                } else if (res.error.code != undefined) {
                    snifferDownloadHint(0, rows, "错误，请重试！");
                } else {
                    snifferDownloadHint(0, rows, res.error.message);
                }
            },
            onerror: function (err) {
                snifferDownloadHint(0, rows, "1.请检查Aria2下载推送地址是否正确！2.请检查Aria2是否启动！3.请检查网络是否正常！");
            }
        });

    }

    function updateHint(){
        comment();
        sniffer();
    }

    function execute(){
        panelManager();
        updateHint();
    }

    execute();
})();